package com.kx.smartdevice.websocket;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kx.smartdevice.event.CheckStatusEvent;
import com.kx.smartdevice.event.DeviceStatusEvent;
import com.kx.smartdevice.event.DeviceStatusType;
import com.kx.smartdevice.pojo.Humiture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 控制温湿度传感器的WebSocket
 *
 * @ClassName PowerCommandWebSocket
 * @Author Sun
 * @Date 2021/6/2 11:41
 */
@Component
public class HumitureWebSocket extends TextWebSocketHandler {
    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private ApplicationContext context;


    private ConcurrentHashMap<String, WebSocketSession> allClients = new ConcurrentHashMap();//保存设备会话的map


    private ConcurrentHashMap<String, Long> updateTimes = new ConcurrentHashMap();//保存设备最后的会话时间

    /**
     * 设备和 websocket 建立连接之后
     *
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String uuid = (String) session.getAttributes().get("uuid");
        System.err.println("温湿度传感器 建立连接了" + uuid);
        //保存当前会话,在保存前要先看看之前有没有会话,有的话说明是重复连接,需要关闭
        WebSocketSession webSocketSession = allClients.get(uuid);
        allClients.put(uuid, session);//先替换,再移除
        context.publishEvent(new DeviceStatusEvent(uuid, DeviceStatusType.OPEN));
        updateTimes.put(uuid, System.currentTimeMillis());//保存在线时间
        if (webSocketSession != null && webSocketSession.isOpen()) {
            webSocketSession.close();
        }

    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        //获取到传递过来的数据,是一个 json,其中包含了温湿度的数据
        String json = message.getPayload();
        System.err.println("收到的温湿度数据为:"+json);
        //保存到数据库
        String uuid = (String) session.getAttributes().get("uuid");
        updateTimes.put(uuid, System.currentTimeMillis());//保存在线时间
        Humiture humiture = objectMapper.readValue(json, Humiture.class);
        humiture.setDeviceId(uuid);
        context.publishEvent(humiture);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        super.handleTransportError(session, exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String uuid = (String) session.getAttributes().get("uuid");
        allClients.remove(uuid);
        context.publishEvent(new DeviceStatusEvent(uuid, DeviceStatusType.CLOSE));//设置为关闭
    }
    @EventListener
    public void onEvent(CheckStatusEvent event) {
//        //检查设备的在线状态,以免有因为断点 断网导致的被动离线
//        allClients.forEach((uuid,session)->{
//            try {
//                //给设备发送数据,如果失败了会出现异常,出现异常代表断线了
//                session.sendMessage(new TextMessage(""));
//            }catch (Exception e){
//               e.printStackTrace();
//               //出现异常就更新设备状态为离线
//                System.err.println(uuid + "离线了");
//                context.publishEvent(new DeviceStatusEvent(uuid,DeviceStatusType.CLOSE));
//            }
//
//        });
        updateTimes.forEach((uuid,time)->{
            //time 是最后一次更新时间
            if (System.currentTimeMillis()-time>60000) {
                System.err.println("设备" + uuid + "已经离线了");
                WebSocketSession webSocketSession = allClients.get(uuid);
                allClients.remove(uuid);
                updateTimes.remove(uuid);
                //发送更新状态的事件
                if (webSocketSession != null && webSocketSession.isOpen()) {
                    try {
                        webSocketSession.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

        });
    }
}
